Unsafe包很有意思,源码中短短几行代码,剩下更多的是注释,初略一看感觉并不重要,其实恰恰相反,很多package中都有它的影子,比如reflect
先从包名讲起,unsafe - 不安全,为什么不安全呢? Package unsafe contains operations that step around the type safety of Go programs
- A pointer value of any type can be converted to a Pointer.
- A Pointer can be converted to a pointer value of any type.
- A uintptr can be converted to a Pointer.
- A Pointer can be converted to a uintptr.
简单来说就是
指针 <—> unsafe.Pointer <—> unitptr
例子 - 强制转换类型
type stringHeader struct {
Data unsafe.Pointer
Len int
}
var s stinrg = “abc"
// *string -> unsafe.Pointer -> *stringHeader
hdr := (*stringHeader)(unsafe.Pointer(&s))
println(&s) // 0xc42000e260
println(&hdr.Data) // 0xc42000e260
println(&hdr.Len) // 0xc42000e268
hdr.Data = unsafe.Pointer(&b[3])
hdr.Len = int(b[1])<<8 | int(b[2])
例子 - 通过位置获取值
// 数组
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + x)
}
func main() {
ints := []int64{1, 22, 123} // 数组
println(&ints[2]) // 第三个成员的地址 0xc42003bf70
up := add(unsafe.Pointer(&ints[0]), 2*unsafe.Sizeof(ints[0])) // 根据成员的size,移动Pointer到目标位置
println((*int)(up)) // 通过add方法移动到的地址 0xc42003bf70
println(*(*int)(up)) // 地址对应的值
}
最后一个例子 - 通过指针强制转换和移动位置修改私有成员
文件夹 pointer 中定义一个P的类,P的成员,i和s,都是私有类型,所以只能查看(GetI, GetS公有)而不能修改
package pointer
type P struct {
i int32
s string
}
func (p *P) GetI() int32 {
return p.i
}
func (p *P) GetS() string {
return p.s
}
然后在包外写一个main文件
package main
import (
"pointer"
)
func main() {
p := new(pointer.P)
println(p.GetI())
println(p.GetS())
// 修改
pointI := (*int32)(unsafe.Pointer(p))
*pointI = 20
println(p.GetI())
pointS := (*string)(add(unsafe.Pointer(p), uintptr(8)))
*pointS = "我就是我"
println(p.GetS())
}